<!-- 标准版登录 -->

<template>
  <div :id="$options.name" v-bind="loginProp">
    <el-form ref="form" v-bind="formProp">
      <div :id="`${$options.name}-logo`" v-bind="logoProp">{{ logoText }}</div>

      <el-form-item v-bind="accountProp">
        <img :src="accountImg" />
        <el-input
          v-model.trim="one.account"
          :maxlength="one.loginType === 1 ? 20 : 11"
          :placeholder="accountProp.rules[0].message"
          clearable
          @keyup.enter.native="toLogin"
        />
      </el-form-item>

      <el-form-item v-bind="passwordProp">
        <img :src="passwordImg" />
        <el-input
          v-model.trim="one.password"
          :maxlength="one.loginType === 1 ? 20 : 6"
          :placeholder="passwordProp.rules[0].message"
          :show-password="one.loginType === 1"
          clearable
          @keyup.enter.native="toLogin"
        />
        <div v-if="one.loginType === 2" :id="`${$options.name}-send`">
          <span v-if="info.second">{{ info.second }} 秒</span>
          <el-button v-else type="text" @click="toSend">发送验证码</el-button>
        </div>
      </el-form-item>

      <div>
        <el-button :id="`${$options.name}-switch`" type="text" @click="toSwitch">
          <span v-if="one.loginType === 1">验证码登录</span>
          <span v-else>账号密码登录</span>
        </el-button>
      </div>

      <el-button :id="`${$options.name}-submit`" type="primary" @click="toLogin">
        <span>登</span>
        <span>录</span>
      </el-button>
    </el-form>

    <Verify
      ref="verify"
      :captcha-type="'blockPuzzle'"
      :img-size="{ width: '400px', height: '200px' }"
      @success="startOne()"
    />
  </div>
</template>

<script>
// ============================== 导入依赖 ============================== //

import CORE from '@/CORE'
import axios from 'axios'
import store from './store'

// ============================== 导出组件 ============================== //

export default {
  /**
   * 名称定义 (实际使用名称)
   */
  name: 'Login',

  /**
   * 混入列表 (配置选项合并)
   */
  mixins: [CORE.mixStore(store), CORE.mixLoop(1)],

  /**
   * 组件导入 (Abc.vue + Abc/index.vue)
   */
  ...CORE.components(require.context('./', true, /vue$/)),

  /**
   * 状态数据 (函数返回对象)
   */
  data() {
    return {
      TIME: CORE.TIME, // 借助 data 将 TIME 变为可响应对象
    }
  },

  /**
   * 计算属性 (慎用箭头函数)
   */
  computed: {
    /**
     * LOGO 文本
     */
    logoText: () => process.env.VUE_APP_LOGO_TEXT,

    /**
     * 登录属性
     */
    loginProp() {
      return {
        class: `${this.$options.name}-${process.env.VUE_APP_TAG}`,
        style: { backgroundImage: this.getBgImg('bg') },
      }
    },

    /**
     * LOGO 属性
     */
    logoProp() {
      if (this.logoText) return null
      return {
        style: { backgroundImage: this.getBgImg('logo') },
      }
    },

    /**
     * 表单属性
     */
    formProp() {
      return {
        model: this.one,
        labelPosition: 'right',
      }
    },

    /**
     * 账号图片
     */
    accountImg: () => require('./img/icon-user.png'),

    /**
     * 密码图片
     */
    passwordImg: () => require('./img/icon-pwd.png'),

    /**
     * 账号属性
     */
    accountProp() {
      const { one: { loginType } } = this
      const label = loginType === 1 ? '账号' : '手机号'
      const message = `请输入${label}`
      const validator = loginType === 1 ? null : (rule, value, callback) => {
        const errMsg = CORE.checkPhone(value)
        if (value && errMsg) callback(new Error(errMsg))
        else callback()
      }
      return {
        key: `account-${loginType}`,
        id: `${this.$options.name}-account`,
        prop: 'account',
        label,
        required: true,
        rules: [{ required: true, message }, { validator }],
      }
    },

    /**
     * 密码属性
     */
    passwordProp() {
      const { one: { loginType } } = this
      const className = loginType === 1 ? null : `${this.$options.name}-verify-code`
      const label = loginType === 1 ? '密码' : '验证码'
      const message = `请输入${label}`
      const validator = loginType === 1 ? null : (rule, value, callback) => {
        if (!/^\d{6}$/.test(value)) callback(new Error('六位数字'))
        else callback()
      }
      return {
        key: `password-${loginType}`,
        id: `${this.$options.name}-password`,
        class: className,
        prop: 'password',
        label,
        required: true,
        rules: [{ required: true, message }, { validator }],
      }
    },

    /**
     * 重定向路径
     */
    redirect() {
      const matched = /redirect=([^&]+)/.exec(location.search)
      return matched ? matched[1] : process.env.VUE_APP_RUN.replace(/login$/, 'admin')
    },
  },

  /**
   * 监听属性 (深度 deep 首次 immediate)
   */
  watch: {
    /**
     * 监听单项就绪
     */
    async readyOne(ready) {
      if (ready) {
        if (process.env.VUE_APP_DEBUG_PORT) CORE.MSG.success('登录：成功') // 调试模式
        else location.href = this.redirect // 路径跳转
      }
    },
  },

  /**
   * 创建完成 (先抽取再调用)
   */
  created() {
    axios.get(CORE.asset('LOGIN_CONFIG.json'))
      .then(({ data }) => CORE.merge(this.MAP, CORE.json(data)))
      .catch(() => null)
  },

  /**
   * 本地方法 (轻量重要在前)
   */
  methods: {
    /**
     * 按秒循环 (可覆盖)
     */
    toLoop() {
      const { one: { loginType }, info } = this
      if (loginType === 2 && info.second) this.info.second--
    },

    /**
     * 切换登录方式
     */
    toSwitch(tab) {
      const loginType = CORE.isComponent(tab) ? +tab.name : this.one.loginType === 1 ? 2 : 1
      Object.assign(this.one, { account: '', password: '', loginType })
      this.info.second = 0
    },

    /**
     * 发送验证码 (重复点击时，错误可以闪烁提示)
     */
    async toSend() {
      const { $refs: { form } } = this

      form.clearValidate()
      await this.$nextTick()
      form.validateField('account', (err) => {
        !err && this.startInfo()
      })
    },

    /**
     * 点击登录 (重复点击时，错误可以闪烁提示)
     */
    async toLogin() {
      const { $refs: { form, verify } } = this

      form.clearValidate()
      await this.$nextTick()
      form.validate((valid) => {
        if (valid) this.MAP.hasVerify ? verify.show() : this.startOne()
      })
    },

    /**
     * 获取背景图片
     */
    getBgImg(name) {
      const url = CORE.asset(`login/${name}.png`)
      return `url(${url})`
    },
  },
}
</script>

<style lang="scss">
@import './index.scss';
</style>
